"""
k-近邻算法
"""

import numpy as np
import operator


def create_data_set():
    group: np.ndarray = np.array([[1.0, 1.0], [1.0, 2.0], [5.0, 4.0], [5.0, 5.0]])
    labels = ['B', 'B', 'A', 'A']
    return group, labels


def classify0(in_x: list, data_set: np.ndarray, labels, k: int):
    """
    计算输入点的分类
    :param in_x: 输入待分类向量
    :param data_set: 样本向量
    :param labels: 样本标签
    :param k: 近邻点的数量
    :return:
    """
    # 样本数据的条数
    data_set_size: int = data_set.shape[0]

    # 输入向理和每个样本向量之间的差。也就相当于输入点与样本点的x轴距离和y轴距离，tile方法是复制矩阵，第二个参数指定按行和列复制的数目，样本向量有几个，就把输入向量复制成几个
    diff_mat: np.ndarray = np.tile(in_x, (data_set_size, 1)) - data_set

    #####################################
    #    勾股定理处输入点与每个样本点间的距离  #
    #####################################
    # 向量差的平方的数组。      准备用于勾股定理
    sq_diff_mat: np.ndarray = diff_mat ** 2
    # 距离平方的数组。         算出输入点与样本点之间的距离的平方，就是勾股定理的弦的平方
    sq_distances: np.ndarray = sq_diff_mat.sum(axis=1)
    # 距离一维数组。           进行开方运算，得到弦长，也就是输入点与样本点间的标量距离
    distances: np.ndarray = sq_distances ** 0.5

    # 将数组中的元素排序，但是不关心元素的值，只保留元素原来的索引
    sorted_dist_indices = distances.argsort()

    # 定义一个元组
    class_count: dict = {}
    for i in range(k):
        # 循环第一次时，sorted_dist_indices数组中的第一个元素（下标为0）是距离数组中距离值最短的元素的原索引，取出其对应的样本点的标签
        vote_i_label: str = labels[sorted_dist_indices[i]]
        # class_count元组中存放各类别的打分，每取到一个距离较近的样本点所属的类型，就给对应元组中的类别加一分
        class_count[vote_i_label] = class_count.get(vote_i_label, 0) + 1
    # 最后将元组中的元素按打分由高到低排序
    sorted_class_count = sorted(class_count.items(), key=operator.itemgetter(1), reverse=True)
    # 第一个元素是打分最高的，那输入点就归到对应的类别
    return sorted_class_count[0][0]


def file2matrix(filename):
    fr = open(filename)



def run():
    group, labels = create_data_set()
    result = classify0([4, 4], group, labels, 3)
    print(result)


run()
